package com.google.code.mochaccino.framework.utils;
/*
 * Copyright 2012 Claude Houle claude.houle@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;

/**
 * Randomizer Utilities that basically use the standard random class from the JDK but do possess
 * some utilities method to generate BigDecimal or Big Integer which are not available into the
 * standard JDK API.
 */
public class Randomizer {

	private static final int    RANDOM_BYTES_MAX_LENGTH = 95;
	private static final int    RANDOM_BYTES_MIN_LENGTH = 2;
	private              Random randomizer              = null;

	public Randomizer() {
		this( false );
	}

	/** Constructor */
	public Randomizer( boolean secure ) {
		if ( secure ) {
			randomizer = new SecureRandom();
		} else {
			randomizer = new Random();
		}
	}

	/** Next Big Decimal */
	public BigDecimal nextBigDecimal( BigDecimal min, BigDecimal max ) {
		return new BigDecimal( nextBigInteger( min.toBigInteger(), max.toBigInteger() ), Math.max( min.scale(), max.scale() ) );
	}

	/** Next Big Integer */
	public BigInteger nextBigInteger( BigInteger min, BigInteger max ) {
		BigInteger result = new BigInteger( randomizer.nextBoolean() ? 1 : -1, nextByteArray( nextInt( 2, 95 ) ) );
		while ( (result.compareTo( min ) < 0) || (result.compareTo( max ) > 0) ) {
			result = new BigInteger( randomizer.nextBoolean() ? 1 : -1, nextByteArray( nextInt( RANDOM_BYTES_MIN_LENGTH, RANDOM_BYTES_MAX_LENGTH ) ) );
		}
		return result;
	}

	/** Next Byte Array */
	public byte[] nextByteArray( int bitCount ) {
		if ( bitCount == 0 ) {
			return new byte[] { };
		}
		int bytesCount = (bitCount + 7) / 8;
		byte[] array = new byte[bytesCount];
		if ( bytesCount > 0 ) {
			randomizer.nextBytes( array );
			int excess = 8 * bytesCount - bitCount;
			array[0] &= (1 << (8 - excess)) - 1;
		}
		return array;
	}

	/** Next Double */
	public double nextDouble( double min, double max ) {
		return (randomizer.nextDouble() * (max - min)) + min;
	}

	/** Next Float */
	public float nextFloat( float min, float max ) {
		return (randomizer.nextFloat() * (max - min)) + min;
	}

	/** Next Int */
	public int nextInt( int min, int max ) {
		return (int) (randomizer.nextDouble() * (max - min)) + min;
	}

	/** Next Long */
	public long nextLong( long min, long max ) {
		return (long) (randomizer.nextDouble() * (max - min)) + min;
	}
}
